#include "App_At_Command.h"

#include <ctype.h>  // 用于tolower函数
#include <stdlib.h>
#include <string.h>  // 用于strcspn函数

#include "App_Mac.h"
#include "board.h"
#include "flash-board.h"
#include "log.h"
#include "system.h"
#include "usart-board.h"

#define COMMAND_HANDLER(cmd, at)                                                                                       \
    do {                                                                                                               \
        const char* sub = #cmd;                                                                                        \
        if (strncmp(command, sub, strlen(sub)) == 0) {                                                                 \
            command += strlen(sub);                                                                                    \
            if (cmd##Handler(command) == CL_FAIL) {                                                                    \
                LOG_PRINTF(LL_DEBUG, "Error,normal format: %s\r\n", at);                                               \
            } else {                                                                                                   \
                LOG_PRINTF(LL_DEBUG, "OK\r\n");                                                                        \
            }                                                                                                          \
            return CL_OK;                                                                                              \
        }                                                                                                              \
    } while (0)

int IsTerminateChar(char ch)
{
    return (ch == '{' || ch == '}' || ch == '[' || ch == ']' || ch == ',' || ch == ' ');
}

int IsNumber(char ch)
{
    return isdigit(ch) || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F');
}

int WordWrap(const char* str, char* word, int max)
{
    const char* pStr = str;
    int index = 0;
    int flag = 0;
    while (*pStr != '\0') {
        char ch = *pStr++;
        if (IsTerminateChar(ch)) {
            if (index > 0) {
                return index;
            }
            word[index++] = ch;
            word[index] = '\0';
            return index;
        } else if (IsNumber(ch) && flag != 2) {
            word[index++] = ch;
            word[index] = '\0';
            flag = 1;
        } else {
            if (index != 0 && isdigit(word[0])) {
                return -1;
            }
            word[index++] = ch;
            word[index] = '\0';
            flag = 2;
        }
    }
    return index;
}

int DitchQueueHex(const char* str, int* out_len, int32_t out[])
{
    int flag[5] = {0};
    int flag_top = 0;
    int index = 0;
    int step_len = 0;
    int len = 0;
    char token[16] = {0};

    while ((len = WordWrap(str, token, sizeof(token))) > 0) {
        str += len;
        step_len += len;
        if (strcmp(token, "{") == 0) {
            if (flag_top == 0) {
                index = 0;
            }
            flag[++flag_top] = 1;
        } else if (strcmp(token, "}") == 0) {
            if (flag[flag_top] != 1) {
                return -1;
            }
            flag[flag_top--] = 0;  // 出栈
            break;
        } else if (strcmp(token, "[") == 0) {
            if (flag_top == 0) {
                index = 0;
            }
            flag[++flag_top] = 2;
        } else if (strcmp(token, "]") == 0) {
            if (flag[flag_top] != 2) {
                return -1;
            }
            flag[flag_top--] = 0;  // 出栈
        } else if (strcmp(token, ",") == 0) {
        } else if (strcmp(token, " ") == 0) {
        } else {
            if (flag[flag_top] == 2) {
                out[index++] = strtol(token, NULL, 16);
            } else {
                out[index++] = strtol(token, NULL, 10);
            }
        }
    }
    *out_len = index;
    return step_len;
}

int SYSINFOHandler(char* command)
{
    DumpSystemInfo();
    return CL_OK;
}

int STATUSHandler(char* command)
{
    LOG_PRINTF(LL_DEBUG, "Status = %u\r\n", SystemLoRaData.systemState.state);
    LOG_PRINTF(LL_DEBUG,
               "txRuning = %u, txSuccess = %u, txFailed = %u, Joining = %u, JoinSucess = %u, JoinFailed = %u,"
               "linkCheck = %u, deviceTiming = %u, deviceTime = %u, mutexState = %u"
#if defined(CONFIG_DTU_485)
               ", rs485SampleFirst = %u"
#endif
               ,
               SystemLoRaData.systemState.flagBit.loraTxRunning, SystemLoRaData.systemState.flagBit.loraTxSuccess,
               SystemLoRaData.systemState.flagBit.loraJoinFailed, SystemLoRaData.systemState.flagBit.loraJoin,
               SystemLoRaData.systemState.flagBit.loraJoinSuccess, SystemLoRaData.systemState.flagBit.loraJoinFailed,
               SystemLoRaData.systemState.flagBit.loraLinkCheck, SystemLoRaData.systemState.flagBit.loraDeviceTiming,
               SystemLoRaData.systemState.flagBit.loraDeviceTime, SystemLoRaData.systemState.flagBit.loraMutexState
#if defined(CONFIG_DTU_485)
               ,
               SystemLoRaData.systemState.flagBit.rs485SampleFirst
#endif
    );
    return CL_OK;
}

int PRINTFHandler(char* command)
{
    int printFlag = 0;
    const char* ptr = command;
    if (*ptr == '?')  // AT+PRINTF?
    {
        AT_PRINTF("AT Read done.\r\n");
        if (g_log_level) {
            printFlag = 1;
        } else {
            printFlag = 0;
        }
        LOG_PRINTF(LL_DEBUG, "+PRINTF:%d\r\n", printFlag);
        return CL_OK;
    } else if (*ptr == '=')  // AT+PRINTF=
    {
        ptr++;
        printFlag = atoi(ptr);
        if (printFlag == 1) {
            g_log_level = LL_ALL;
            return CL_OK;
        } else if (printFlag == 0) {
            g_log_level = LL_NONE;
            return CL_OK;
        }
        return CL_FAIL;
    }
    return CL_FAIL;
}

int COMFIRMHandler(char* command)
{
    uint8_t confirm = 0;

    char* ptr = command;
    if (*ptr == '?')  // AT+CONFIRM?
    {
        LOG_PRINTF(LL_DEBUG, "+CONFIRM:%d\r\n", SystemParmData.txConfirmedType);
        return CL_OK;
    } else if (*ptr == '=')  // AT+PRINTF=
    {
        ptr++;
        confirm = atoi(ptr);

        if (confirm == 0) {
            SystemParmData.txConfirmedType = 0;  // unconfitm
        } else {
            SystemParmData.txConfirmedType = 1;  // confirm
        }

        SystemParmDataStorage(SYSTEM_PARAM_DATA_ADDR);
        // SystemParmDataStorage(SYSTEM_PARAM_DATA_BACKUP_ADDR);
        return CL_OK;
    }
    return CL_FAIL;
}

int OTAAHandler(char* command)
{
    uint8_t confirm = 0;
    char* ptr = command;
    if (*ptr == '?') {
        LOG_PRINTF(LL_DEBUG, "+OTAA:%d\r\n", SystemParmData.activitionType);
        return CL_OK;
    } else if (*ptr == '=') {
        ptr++;
        confirm = atoi(ptr);

        if (confirm == 0) {
            SystemParmData.activitionType = 0;
        } else {
            SystemParmData.activitionType = 1;
        }

        SystemParmDataStorage(SYSTEM_PARAM_DATA_ADDR);
        // SystemParmDataStorage(SYSTEM_PARAM_DATA_BACKUP_ADDR);
        return CL_OK;
    }
    return CL_FAIL;
}

int DEVEUIHandler(char* command)
{
    char* ptr = command;
    if (*ptr == '?') {
        char Buf[64];
        HexToString(Buf, (uint8_t*)(SystemParmData.devEui), sizeof(SystemParmData.devEui));

        LOG_PRINTF(LL_DEBUG, "+DEVEUI: %s\r\n", Buf);
        return CL_OK;
    } else if (*ptr == '=') {
        ptr++;
        StringToHex((uint8_t*)(SystemParmData.devEui), (void*)ptr, strlen((const char*)ptr));
        for (uint8_t i = 0; i < sizeof(SystemParmData.devEui); i++) {
            LOG_PRINTF(LL_DEBUG, "%02x,", SystemParmData.devEui[i]);
        }
        LOG_PRINTF(LL_DEBUG, "\r\n");

        SystemParmDataStorage(SYSTEM_PARAM_DATA_ADDR);
        // SystemParmDataStorage(SYSTEM_PARAM_DATA_BACKUP_ADDR);

        return CL_OK;
    }
    return CL_FAIL;
}

int APPEUIHandler(char* command)
{
    char* ptr = command;
    if (*ptr == '?') {
        char Buf[64];
        HexToString(Buf, (uint8_t*)SystemParmData.appEui, sizeof(SystemParmData.appEui));
        LOG_PRINTF(LL_DEBUG, "+APPEUI: %s\r\n", Buf);
        return CL_OK;
    } else if (*ptr == '=') {
        ptr++;
        StringToHex((uint8_t*)SystemParmData.appEui, (void*)ptr, strlen((const char*)ptr));
        for (uint8_t i = 0; i < sizeof(SystemParmData.appEui); i++) {
            LOG_PRINTF(LL_DEBUG, "%02x,", SystemParmData.appEui[i]);
        }
        LOG_PRINTF(LL_DEBUG, "\r\n");
        SystemParmDataStorage(SYSTEM_PARAM_DATA_ADDR);
        // SystemParmDataStorage(SYSTEM_PARAM_DATA_BACKUP_ADDR);
        return CL_OK;
    }
    return CL_FAIL;
}

int APPKEYHandler(char* command)
{
    char* ptr = command;
    if (*ptr == '?') {
        char Buf[64];
        HexToString(Buf, (uint8_t*)SystemParmData.appKey, sizeof(SystemParmData.appKey));
        LOG_PRINTF(LL_DEBUG, "+APPKEY: %s\r\n", Buf);
        return CL_OK;
    } else if (*ptr == '=') {
        ptr++;
        StringToHex((uint8_t*)SystemParmData.appKey, (void*)ptr, strlen((const char*)ptr));
        for (uint8_t i = 0; i < sizeof(SystemParmData.appKey); i++) {
            AT_PRINTF("%02x,", SystemParmData.appKey[i]);
        }
        AT_PRINTF("\r\n");

        SystemParmDataStorage(SYSTEM_PARAM_DATA_ADDR);
        // SystemParmDataStorage(SYSTEM_PARAM_DATA_BACKUP_ADDR);
        return CL_OK;
    }
    return CL_FAIL;
}

int ADRHandler(char* command)
{
    uint8_t adrCtrl = 0;
    char* ptr = command;
    if (*ptr == '?') {
        LOG_PRINTF(LL_DEBUG, "+ADR:%d\r\n", SystemParmData.adrType);
        return CL_OK;
    } else if (*ptr == '=') {
        ptr++;
        adrCtrl = *ptr - '0';

        if ((adrCtrl != 0) && (adrCtrl != 1)) {
            LOG_PRINTF(LL_DEBUG, "BAD PARM\r\n");
            return CL_FAIL;
        }

        SystemParmData.adrType = adrCtrl;
        SystemParmDataStorage(SYSTEM_PARAM_DATA_ADDR);
        // SystemParmDataStorage(SYSTEM_PARAM_DATA_BACKUP_ADDR);

        return CL_OK;
    }
    return CL_FAIL;
}

int PORTHandler(char* command)
{
    char* ptr = command;
    if (*ptr == '?') {
        LOG_PRINTF(LL_DEBUG, "+PORT:%d\r\n", SystemParmData.appPort);
        return CL_OK;
    } else if (*ptr == '=') {
        ptr++;
        uint8_t appPort = 0;

        appPort = atoi(ptr);
        AT_PRINTF("appPort = %d\r\n", appPort);
        if ((appPort > 0) && (appPort < 224)) {
            SystemParmData.appPort = appPort;
            SystemParmDataStorage(SYSTEM_PARAM_DATA_ADDR);
            // SystemParmDataStorage(SYSTEM_PARAM_DATA_BACKUP_ADDR);
            return CL_OK;
        }
    }
    return CL_FAIL;
}

int NBTRIALSHandler(char* command)
{
    char* ptr = command;
    if (*ptr == '?') {
        LOG_PRINTF(LL_DEBUG, "+NBTRIALS:%d\r\n", SystemParmData.appDataNbTrials);
        return CL_OK;
    } else if (*ptr == '=') {
        ptr++;
        uint8_t appDataNbTrials = 0;

        appDataNbTrials = atoi(ptr);
        AT_PRINTF("appDataNbTrials = %d\r\n", appDataNbTrials);
        if ((appDataNbTrials > 0) && (appDataNbTrials < 9)) {
            SystemParmData.appDataNbTrials = appDataNbTrials;

            SystemParmDataStorage(SYSTEM_PARAM_DATA_ADDR);
            // SystemParmDataStorage(SYSTEM_PARAM_DATA_BACKUP_ADDR);
            return CL_OK;
        }
    }
    return CL_FAIL;
}

int CLASSHandler(char* command)
{
    char* ptr = command;
    if (*ptr == '?') {
        LOG_PRINTF(LL_DEBUG, "+CLASS:%d\r\n", SystemParmData.deviceClass);
        return CL_OK;
    } else if (*ptr == '=') {
        ptr++;
        uint8_t classType = 0;
        classType = *ptr - '0';

        if ((classType != 0) && (classType != 2)) {
            LOG_PRINTF(LL_DEBUG, "NOT SUPPORT\n");
            return CL_FAIL;
        }

        SystemParmData.deviceClass = classType;

        SystemParmDataStorage(SYSTEM_PARAM_DATA_ADDR);
        // SystemParmDataStorage(SYSTEM_PARAM_DATA_BACKUP_ADDR);
        return CL_OK;
    }
    return CL_FAIL;
}

int CHANNELHandler(char* command)
{
    char* ptr = command;
    if (*ptr == '?') {
        LOG_PRINTF(LL_DEBUG, "+CHANNEL:%04x,%04x,%04x,%04x,%04x,%04x\r\n", SystemParmData.channelsMask[0],
                   SystemParmData.channelsMask[1], SystemParmData.channelsMask[2], SystemParmData.channelsMask[3],
                   SystemParmData.channelsMask[4], SystemParmData.channelsMask[5]);
        return CL_OK;
    } else if (*ptr == '=') {
        ptr++;

        uint16_t channelsMaskTemp[6] = {0};
        uint8_t buffer[2] = {0};

        char* str = ptr;
        AT_PRINTF("str = %s\r\n", str);

        char* temp = strtok(str, ",");
        AT_PRINTF("temp = %s\r\n", temp);

        memset1(buffer, 0, sizeof(buffer));
        StringToHex(buffer, temp, 4);
        channelsMaskTemp[0] = (uint16_t)(buffer[0] << 8) | (buffer[1]);

        temp = strtok(NULL, ",");
        memset1(buffer, 0, sizeof(buffer));
        StringToHex(buffer, temp, 4);
        channelsMaskTemp[1] = (uint16_t)(buffer[0] << 8) | (buffer[1]);

        temp = strtok(NULL, ",");
        memset1(buffer, 0, sizeof(buffer));
        StringToHex(buffer, temp, 4);
        channelsMaskTemp[2] = (uint16_t)(buffer[0] << 8) | (buffer[1]);

        temp = strtok(NULL, ",");
        memset1(buffer, 0, sizeof(buffer));
        StringToHex(buffer, temp, 4);
        channelsMaskTemp[3] = (uint16_t)(buffer[0] << 8) | (buffer[1]);

        temp = strtok(NULL, ",");
        memset1(buffer, 0, sizeof(buffer));
        StringToHex(buffer, temp, 4);
        channelsMaskTemp[4] = (uint16_t)(buffer[0] << 8) | (buffer[1]);

        temp = strtok(NULL, ",");
        memset1(buffer, 0, sizeof(buffer));
        StringToHex(buffer, temp, 4);
        channelsMaskTemp[5] = (uint16_t)(buffer[0] << 8) | (buffer[1]);

        AT_PRINTF("ChannelMask = ");
        for (uint16_t i = 0; i < 6; i++) {
            AT_PRINTF("%04x,", channelsMaskTemp[i]);
        }
        AT_PRINTF("\r\n");

        memcpy((uint8_t*)SystemParmData.channelsMask, channelsMaskTemp, sizeof(channelsMaskTemp));
        SystemParmDataStorage(SYSTEM_PARAM_DATA_ADDR);
        // SystemParmDataStorage(SYSTEM_PARAM_DATA_BACKUP_ADDR);

        return CL_OK;
    }
    return CL_FAIL;
}

int POWERHandler(char* command)
{
    char* ptr = command;
    if (*ptr == '?') {
        LOG_PRINTF(LL_DEBUG, "+POWER:%d\r\n", SystemParmData.power);
        return CL_OK;
    } else if (*ptr == '=') {
        ptr++;

        int8_t channelTxPower = -1;

        channelTxPower = *ptr - '0';

        if ((channelTxPower >= TX_POWER_0) && (channelTxPower <= TX_POWER_7)) {
            MibRequestConfirm_t mibReq;
            mibReq.Type = MIB_CHANNELS_TX_POWER;
            mibReq.Param.ChannelsTxPower = channelTxPower;
            if (LoRaMacMibSetRequestConfirm(&mibReq) != LORAMAC_STATUS_OK) {
                LOG_PRINTF(LL_DEBUG, "ERROR\r\n");
                return CL_FAIL;
            }

            SystemParmData.power = channelTxPower;
            SystemParmDataStorage(SYSTEM_PARAM_DATA_ADDR);
            // SystemParmDataStorage(SYSTEM_PARAM_DATA_BACKUP_ADDR);
            return CL_OK;
        }
    }
    return CL_FAIL;
}

int DATARATEHandler(char* command)
{
    char* ptr = command;
    if (*ptr == '?') {
        LOG_PRINTF(LL_DEBUG, "+DATARATE:%d\r\n", SystemParmData.appDataRate);
        return CL_OK;
    } else if (*ptr == '=') {
        ptr++;

        int8_t appDataRate = *ptr - '0';

        if ((appDataRate >= DR_0) && (appDataRate <= DR_5)) {
            SystemParmData.appDataRate = appDataRate;

            SystemParmDataStorage(SYSTEM_PARAM_DATA_ADDR);
            // SystemParmDataStorage(SYSTEM_PARAM_DATA_BACKUP_ADDR);
            return CL_OK;
        }
    }
    return CL_FAIL;
}

int RX2PARMHandler(char* command)
{
    MibRequestConfirm_t mibReq;
    char* ptr = command;
    if (*ptr == '?') {
        LOG_PRINTF(LL_DEBUG, "+RX2PARM:%lu,%d\r\n", SystemParmData.rx2Channel.Frequency,
                   SystemParmData.rx2Channel.Datarate);
        return CL_OK;
    } else if (*ptr == '=') {
        ptr++;

        char* str = ptr;
        AT_PRINTF("str = %s\r\n", str);

        char* temp = strtok(str, ",");
        AT_PRINTF("temp = %s\r\n", temp);
        mibReq.Param.Rx2Channel.Frequency = atol(temp);  // ��ȡ����
        AT_PRINTF("frequency = %lu\r\n", mibReq.Param.Rx2Channel.Frequency);
        temp = strtok(NULL, ",");
        mibReq.Param.Rx2Channel.Datarate = atoi(temp);
        if ((mibReq.Param.Rx2Channel.Datarate < DR_0) || (mibReq.Param.Rx2Channel.Datarate > DR_5)) {
            LOG_PRINTF(LL_DEBUG, "BAD PARM\r\n");
            return CL_FAIL;
        }
        SystemParmData.rx2Channel.Frequency = mibReq.Param.Rx2Channel.Frequency;
        SystemParmData.rx2Channel.Datarate = mibReq.Param.Rx2Channel.Datarate;

        SystemParmDataStorage(SYSTEM_PARAM_DATA_ADDR);
        // SystemParmDataStorage(SYSTEM_PARAM_DATA_BACKUP_ADDR);
        return CL_OK;
    }
    return CL_FAIL;
}

int SENDHandler(char* command)
{
    char* ptr = command;
    if (*ptr++ == '=') {
        uint8_t appData[128] = {0};
        uint16_t appSize = 0;
        uint8_t token[128] = {0};
        int len = 0;

        // memset((uint8_t*)SystemLoRaData.appData, 0, sizeof(SystemLoRaData.appData));
        // SystemLoRaData.appDataSize = strlen(ptr);  // 数据的长度
        strcpy((uint8_t*)appData, ptr);
        appSize = strlen(appData);
        AT_PRINTF("data = %s\r\n", appData);

        SendAppData(appData, appSize);
        return CL_OK;
    }
    return CL_FAIL;
}

int REBOOTHandler(char* command)
{
    char* ptr = command;
    if (*ptr == '=') {
        int8_t reboot = *ptr - '0';

        if (reboot > 0) {
            AT_PRINTF("reboot system\r\n");
            NVIC_SystemReset();
            return CL_OK;
        }
    }
    return CL_FAIL;
}

int COMHandler(char* command)
{
    char* ptr = command;
    if (*ptr == '?') {
        DumpComParams();
        return CL_OK;
    } else if (*ptr++ == '=') {
        int len = 0;
        int index = 0;
        char token[16] = {0};

        while ((len = WordWrap(ptr, token, sizeof(token)))) {
            ptr += len;
            if (IsTerminateChar(token[0])) {
                continue;
            }
            if (index == 0) {
                SystemParmData.baudRate = (uint32_t)atoi(token);
            } else if (index == 1) {
                if (token[0] == 'N') {
                    SystemParmData.parityMode = UART_PARITY_NO;
                } else if (token[0] == 'E') {
                    SystemParmData.parityMode = UART_PARITY_EVEN;
                } else {
                    SystemParmData.parityMode = UART_PARITY_ODD;
                }
            } else if (index == 2) {
                SystemParmData.dataWidth = (uint8_t)atoi(token);
            } else if (index == 3) {
                if (token[0] == '2') {
                    SystemParmData.stopBit = 2;
                } else {
                    SystemParmData.stopBit = 1;
                }
            }
            ++index;
        }
        DumpComParams();
        SystemParmDataStorage(SYSTEM_PARAM_DATA_ADDR);
        // SystemParmDataStorage(SYSTEM_PARAM_DATA_BACKUP_ADDR);

        return CL_OK;
    }
    return CL_FAIL;
}

int DUTYHandler(char* command)
{
    char* ptr = command;
    if (*ptr == '?') {
        LOG_PRINTF(LL_DEBUG, "+DUTY:%d\r\n", SystemParmData.txDutyCycleTime);
        return CL_OK;
    } else if (*ptr == '=') {
        ptr++;

        SystemParmData.txDutyCycleTime = atoi(ptr);
        SystemParmDataStorage(SYSTEM_PARAM_DATA_ADDR);
        // SystemParmDataStorage(SYSTEM_PARAM_DATA_BACKUP_ADDR);
        return CL_OK;
    }
    return CL_FAIL;
}

int MODELHandler(char* command)
{
    char* ptr = command;

    if (*ptr == '?') {
        DumpDeviceModel();
        return CL_OK;
    } else if (*ptr++ == '=') {
        LoraDeviceModel_t* devModel = NULL;
        char token[16] = {0};
        int index = 0;
        int op = 0;
        int len = 0;

        while ((len = WordWrap(ptr, token, sizeof(token))) > 0) {
            ptr += len;
            // LOG_PRINTF(LL_DEBUG, "index = %d, token = %s\r\n", index, token);
            if (IsTerminateChar(token[0])) {
                continue;
            }
            if (index == 0) {
                if (strcmp(token, "UPDATE") == 0) {
                    op = 0;
                } else if (strcmp(token, "DEL") == 0) {
                    op = 1;
                } else {
                    op = 2;  // ADD
                }
            } else if (index == 1) {
                int modelId = atoi(token);
                // LOG_PRINTF(LL_DEBUG, "modelId = %d, op = %d\r\n", modelId, op);
                if (modelId == 0) {
                    return CL_FAIL;
                }
                devModel = FindDeviceModel(modelId);
                if (op == 2) {
                    if (devModel != NULL) {
                        LOG_PRINTF(LL_DEBUG, "device model exist, %d\r\n", modelId);
                        return CL_FAIL;
                    }
                    devModel = GetEmptyDeviceModel();
                }
                if (devModel == NULL) {
                    LOG_PRINTF(LL_DEBUG, "no more empty device models\r\n");
                    return CL_FAIL;
                }
                devModel->modelId = modelId;
                if (op == 1) {
                    devModel->modelId = 0;
                    LOG_PRINTF(LL_DEBUG, "device model %d deleted\r\n", modelId);
                    return CL_OK;
                }
            } else if (index == 2) {
                if (devModel == NULL) {
                    return CL_FAIL;
                }
                int attrId = atoi(token);
                if (attrId == 0 || !FindDeviceAttr(attrId)) {
                    LOG_PRINTF(LL_DEBUG, "Not find attrId = %d in devices\r\n", attrId);
                    devModel->modelId = 0;
                    return CL_FAIL;
                }
                devModel->attrId = attrId;
                break;
            }
            ++index;
            memset(token, 0, sizeof(token));
        }
        if (devModel == NULL) {
            return CL_FAIL;
        }
        int32_t out[8] = {0};
        int count = 0;
        index = 0;
        while ((len = DitchQueueHex(ptr, &count, out)) > 0) {
            ptr += len;
            if (out[1] > 4 || (4 + out[1]) > count) {
                LOG_PRINTF(LL_DEBUG, "reg length is too bigger\r\n");
                devModel->modelId = 0;
                return CL_FAIL;
            }
            devModel->model[index].acqType = out[0];
            devModel->model[index].regLengh = out[1];
            for (int k = 0; k < devModel->model[index].regLengh; k++) {
                devModel->model[index].regAddr[k] = out[2 + k];
            }
            devModel->model[index].dataOffset = out[devModel->model[index].regLengh + 2];
            devModel->model[index].dataLen = out[devModel->model[index].regLengh + 3];
            LOG_PRINTF(LL_DEBUG, "index = %d, acqType = %u, regLength = %u, dataOffset = %u, dataLen = %u\r\n", index,
                       devModel->model[index].acqType, devModel->model[index].regLengh,
                       devModel->model[index].dataOffset, devModel->model[index].dataLen);
        }
        SystemParmDataStorage(SYSTEM_PARAM_DATA_ADDR);
        // SystemParmDataStorage(SYSTEM_PARAM_DATA_BACKUP_ADDR);
        return CL_OK;
    }
    return CL_FAIL;
}

int DEVICEHandler(char* command)
{
    char* ptr = command;

    if (*ptr == '?') {
        LOG_PRINTF(LL_DEBUG, "Devices format: AT+DEVICE = "
                             "modelId,devAddr---------------------\r\n");
        DumpDevices();
        return CL_OK;
    } else if (*ptr++ == '=') {
        LoraDevice_t loraDevice;
        char* token = NULL;
        int loraIndex = -1;
        int index = 0;
        loraDevice.addrLength = 0;
        token = strtok(ptr, ",");
        while (token != NULL) {
            if (index == 0) {
                loraIndex = atoi(token);
            } else if (index == 1) {
                int modelId = atoi(token);
                LoraDeviceModel_t* devModel = FindDeviceModel(modelId);
                if (devModel == NULL) {
                    LOG_PRINTF(LL_DEBUG,
                               "BAD PARM, Not Find modelId = %d, Please add model "
                               "before(AT+DEVICE)\r\n",
                               modelId);
                    return CL_FAIL;
                }
                loraDevice.modelId = modelId;
            } else {
                char* end;
                loraDevice.devAddr[loraDevice.addrLength++] = (uint8_t)strtol(token, &end, 16);
            }
            token = strtok(NULL, ",");
            ++index;
        }

        if (loraIndex < 0 || loraIndex >= SYSTEM_DEVICE_NUM) {
            LOG_PRINTF(LL_DEBUG, "exceed the max device number %d\r\n", SYSTEM_DEVICE_NUM);
            return CL_FAIL;
        }
        SystemParmData.loraDevice[loraIndex] = loraDevice;
        SystemParmDataStorage(SYSTEM_PARAM_DATA_ADDR);
        // SystemParmDataStorage(SYSTEM_PARAM_DATA_BACKUP_ADDR);
        return CL_OK;
    }
    return CL_FAIL;
}

#if defined(CONFIG_DTU_485)
int ATTRHandler(char* command)
{
    char* ptr = command;
    int data = 0;
    uint8_t i = 0;
    if (*ptr == '?') {
        LOG_PRINTF(LL_DEBUG, "Attribute:\r\n");
        DumpAttrData();
        // LOG_PRINTF(LL_DEBUG, "BAD PARM\r\n");
        // AtSendResponse(ResponseBuf,strlen((const char*)ResponseBuf));
        return CL_OK;
    } else if (*ptr++ == '=') {
        SystemAttributeData_t attrData;
        char* token = NULL;
        int index = 0;

        attrData.attrId = 0;
        attrData.attrCmdLen = 0;
        attrData.attrAddrOffset = 0;
        attrData.attrRegOffset = 0;
        attrData.attrVerifyOffset = 0;

        token = strtok(ptr, ",");
        while (token != NULL) {
            if (index == 0) {
                attrData.attrId = atoi(token);
            } else {
                if (strcmp(token, "CRC") == 0) {
                    attrData.attrVerifyOffset = attrData.attrCmdLen++;
                    attrData.attrVerify = 2;
                } else if (strcmp(token, "CHK") == 0) {
                    attrData.attrVerifyOffset = attrData.attrCmdLen++;
                    attrData.attrVerify = 1;
                } else if (strcmp(token, "ADDR") == 0) {
                    attrData.attrAddrOffset = attrData.attrCmdLen++;
                } else if (strcmp(token, "REG") == 0) {
                    attrData.attrRegOffset = attrData.attrCmdLen++;
                } else {
                    char* end;
                    attrData.attrCmd[attrData.attrCmdLen++] = (uint8_t)strtol(token, &end, 16);
                }
            }

            token = strtok(NULL, ",");
            ++index;
        }

        if (attrData.attrId <= 0) {
            LOG_PRINTF(LL_DEBUG, "BAD PARM, Format [attrId, 16进制命令]\r\n");
            return CL_FAIL;
        }

        int attrIndex = -1;
        for (int i = 0; i < SYSTEM_ATTRIBUTE_NUM; i++) {
            if (SystemParmData.attributeData[i].attrId == 0) {
                attrIndex = i;
                continue;
            }
            if (SystemParmData.attributeData[i].attrId == attrData.attrId) {
                attrIndex = i;
                break;
            }
        }
        if (attrIndex == -1) {
            return CL_FAIL;
        }
        SystemParmData.attributeData[attrIndex] = attrData;

        SystemParmDataStorage(SYSTEM_PARAM_DATA_ADDR);
        // SystemParmDataStorage(SYSTEM_PARAM_DATA_BACKUP_ADDR);
        return CL_OK;
    }
    return CL_FAIL;
}

int DEBUGHandler(char* command)
{
    char* ptr = command;
    int data = 0;
    uint8_t i = 0;
    if (*ptr == '?') {
        LOG_PRINTF(LL_DEBUG, "No status\r\n");
        return CL_OK;
    } else if (*ptr++ == '=') {
        char* token = NULL;
        int index = 0;
        uint8_t cmd[64] = {0};
        token = strtok(ptr, ",");
        do {
            if (token == NULL) {
                break;
            }
            if (strcmp(token, "CRC") == 0) {
                uint16_t crc = App_Crc16(cmd, index);
                cmd[index++] = ((crc >> 8) & 0xff);
                cmd[index++] = crc & 0xff;
            } else if (strcmp(token, "CHK") == 0) {
                uint8_t chk = CheckSum(cmd, index);
                cmd[index++] = chk;
            } else {
                char* end;
                cmd[index++] = (uint8_t)strtol(token, &end, 16);
            }
            token = strtok(NULL, ",");
        } while (1);
        AppSerialDebug(cmd, index);
        return CL_OK;
    }
    return CL_FAIL;
}

int ACQHandler(char* command)
{
    char* ptr = command;
    int data = 0;
    uint8_t i = 0;
    if (*ptr == '?') {
        LOG_PRINTF(LL_DEBUG, "No status\r\n");
        return CL_OK;
    } else if (*ptr++ == '=') {
        char* token = NULL;
        int index = 0;
        uint8_t cmd[64] = {0};
        token = strtok(ptr, ",");
        do {
            if (token == NULL) {
                break;
            }
            if (strcmp(token, "CRC") == 0) {
                uint16_t crc = App_Crc16(cmd, index);
                cmd[index++] = ((crc >> 8) & 0xff);
                cmd[index++] = crc & 0xff;
            } else if (strcmp(token, "CHK") == 0) {
                uint8_t chk = CheckSum(cmd, index);
                cmd[index++] = chk;
            } else {
                char* end;
                cmd[index++] = (uint8_t)strtol(token, &end, 16);
            }
            token = strtok(NULL, ",");
        } while (1);

        uint8_t recv[64] = {0};
        int len = AppSerialCommunication(cmd, index, recv);
        // LOG_PRINTF(LL_DEBUG, "Notify device acquire, index = %d\r\n", i);
        App_Lora_Proto_SendData(recv, len);
        return CL_OK;
    }
    return CL_FAIL;
}
#endif

#if defined(CONFIG_DTU_AI)
int AIHandler(char* command)
{
    char* ptr = command;
    int data = 0;
    uint8_t i = 0;
    if (*ptr == '?') {
        for (i = 0; i < SYSTEM_AI_ATTRIBUTE_NUM; i++) {
            LOG_PRINTF(LL_DEBUG, "+AI:%d,%d,%d,%d,%d,%d\r\n", SystemParmData.aiAttrData[i].attrId,
                       SystemParmData.aiAttrData[i].attrAlarmMinData, SystemParmData.aiAttrData[i].attrAlarmMaxData,
                       SystemParmData.aiAttrData[i].attrAlarmRecoverMinData,
                       SystemParmData.aiAttrData[i].attrAlarmRecoverMaxData, SystemParmData.aiAttrData[i].sampleTime);
        }
        return CL_OK;
    } else if (*ptr == '=') {
        ptr++;
        char* temp = strtok(ptr, ",");
        data = atoi(temp);
        if ((data == 0) || (data > SYSTEM_AI_ATTRIBUTE_NUM)) {
            return CL_FAIL;
        }

        for (i = 0; i < SYSTEM_AI_ATTRIBUTE_NUM; i++) {
            if ((SystemParmData.aiAttrData[i].attrId == 0) || (data == SystemParmData.aiAttrData[i].attrId)) {
                break;
            }
        }

        if (i == SYSTEM_AI_ATTRIBUTE_NUM) {
            LOG_PRINTF(LL_DEBUG, "ID FULL\r\n");
            return CL_FAIL;
        }

        SystemParmData.aiAttrData[i].attrId = data;

        data = 0;
        temp = strtok(NULL, ",");
        data = atoi(temp);
        SystemParmData.aiAttrData[i].attrAlarmMinData = data;

        data = 0;
        temp = strtok(NULL, ",");
        data = atoi(temp);
        SystemParmData.aiAttrData[i].attrAlarmMaxData = data;

        data = 0;
        temp = strtok(NULL, ",");
        data = atoi(temp);
        SystemParmData.aiAttrData[i].attrAlarmRecoverMinData = data;

        data = 0;
        temp = strtok(NULL, ",");
        data = atoi(temp);
        SystemParmData.aiAttrData[i].attrAlarmRecoverMaxData = data;

        data = 0;
        temp = strtok(NULL, ",");
        data = atoi(temp);
        SystemParmData.aiAttrData[i].sampleTime = data;

        SystemParmDataStorage(SYSTEM_PARAM_DATA_ADDR);
        // SystemParmDataStorage(SYSTEM_PARAM_DATA_BACKUP_ADDR);

        return CL_OK;
    }
    return CL_FAIL;
}

#endif

#if defined(CONFIG_DTU_DOUT)
int DOUTHandler(char* command)
{
    char* ptr = command;
    int data = 0;
    uint8_t i = 0;
    if (*ptr == '?') {
        for (i = 0; i < SYSTEM_DOUT_ATTRIBUTE_NUM; i++) {
            LOG_PRINTF(LL_DEBUG, "+DOUT:%d,%d\r\n", SystemParmData.doutAttrData[i].attrId,
                       SystemParmData.doutAttrData[i].attrData);
        }
        return CL_OK;
    } else if (*ptr == '=') {
        ++ptr;
        char* temp = strtok(ptr, ",");
        data = atoi(temp);
        if ((data == 0) || (data > SYSTEM_DOUT_ATTRIBUTE_NUM)) {
            LOG_PRINTF(LL_DEBUG, "BAD PARM\r\n");
            return CL_FAIL;
        }

        for (i = 0; i < SYSTEM_DOUT_ATTRIBUTE_NUM; i++) {
            if ((SystemParmData.doutAttrData[i].attrId == 0) || (data == SystemParmData.doutAttrData[i].attrId)) {
                break;
            }
        }

        if (i == SYSTEM_DOUT_ATTRIBUTE_NUM) {
            LOG_PRINTF(LL_DEBUG, "ID FULL\r\n");
            return CL_FAIL;
        }

        SystemParmData.doutAttrData[i].attrId = data;

        data = 0;
        temp = strtok(NULL, ",");
        data = atoi(temp);
        SystemParmData.doutAttrData[i].attrData = data;

        SystemParmDataStorage(SYSTEM_PARAM_DATA_ADDR);
        // SystemParmDataStorage(SYSTEM_PARAM_DATA_BACKUP_ADDR);

        return CL_OK;
    }
    return CL_FAIL;
}

#endif

#if defined(CONFIG_DTU_DIN)
int DINHandler(char* command)
{
    char* ptr = command;
    int data = 0;
    uint8_t i = 0;
    if (*ptr == '?') {
        for (i = 0; i < SYSTEM_DIN_ATTRIBUTE_NUM; i++) {
            LOG_PRINTF(LL_DEBUG, "+DIN:%d,%d\r\n", SystemParmData.dinAttrData[i].attrId,
                       SystemParmData.dinAttrData[i].attrData);
            return CL_OK;
        }
    } else if (*ptr == '=') {
        ++ptr;
        char* temp = strtok(ptr, ",");
        data = atoi(temp);
        if ((data == 0) || (data > SYSTEM_DIN_ATTRIBUTE_NUM)) {
            LOG_PRINTF(LL_DEBUG, "BAD PARM\r\n");
            return CL_FAIL;
        }

        for (i = 0; i < SYSTEM_DIN_ATTRIBUTE_NUM; i++) {
            if ((SystemParmData.dinAttrData[i].attrId == 0) || (data == SystemParmData.dinAttrData[i].attrId)) {
                break;
            }
        }

        if (i == SYSTEM_DIN_ATTRIBUTE_NUM) {
            LOG_PRINTF(LL_DEBUG, "ID FULL\r\n");
            return CL_FAIL;
        }

        SystemParmData.dinAttrData[i].attrId = data;

        data = 0;
        temp = strtok(NULL, ",");
        data = atoi(temp);
        SystemParmData.dinAttrData[i].attrData = data;

        SystemParmDataStorage(SYSTEM_PARAM_DATA_ADDR);
        // SystemParmDataStorage(SYSTEM_PARAM_DATA_BACKUP_ADDR);

        return CL_OK;
    }
    return CL_FAIL;
}

#endif

int App_At_Command_Parase(uint8_t* commandBuffer, uint8_t commandLen)
{
    char* command = strstr((char*)commandBuffer, "AT+");
    if (command) {
        command += strlen("AT+");
        COMMAND_HANDLER(PRINTF, "AT+PRINTF= [0,1]");
        COMMAND_HANDLER(STATUS, "AT+STATUS?");
        COMMAND_HANDLER(SYSINFO, "AT+SYSINFO?");
        COMMAND_HANDLER(COMFIRM, "AT+COMFIRM=1");
        COMMAND_HANDLER(OTAA, "AT+OTAA=1");
        COMMAND_HANDLER(DEVEUI, "AT+DEVEUI=XXXXXXXXXXXXXXXX");
        COMMAND_HANDLER(APPEUI, "AT+APPEUI=XXXXXXXXXXXXXXXX");
        COMMAND_HANDLER(APPKEY, "AT+APPKEY=XXXXXXXXXXXXXXXX");
        COMMAND_HANDLER(ADR, "AT+ADR=");
        COMMAND_HANDLER(PORT, "AT+PORT=(0,224)");
        COMMAND_HANDLER(NBTRIALS, "AT+NBTRIAL=[0,1,2,3,4,5,6,7,8,9)");
        COMMAND_HANDLER(CLASS, "AT+CLASS=1");
        COMMAND_HANDLER(CHANNEL, "AT+CHANNEL=");
        COMMAND_HANDLER(POWER, "AT+POWER=[0,1,2,3,4,5,6,7]");
        COMMAND_HANDLER(DATARATE, "AT+DATARATE=[0,1,2,3,4,5]");
        COMMAND_HANDLER(RX2PARM, "AT+RX2PARM=freq,datarate");
        COMMAND_HANDLER(SEND, "AT+SEND=XXXXXXX");
        COMMAND_HANDLER(REBOOT, "AT+REBOOT=1");
        COMMAND_HANDLER(DUTY, "AT+DUTY=30");
        COMMAND_HANDLER(COM, "AT+COM=9600,N,8,1");
        COMMAND_HANDLER(DEVICE, "AT+DEVICE=devIndex,modelId,devAddr[<8]");
        COMMAND_HANDLER(MODEL, "AT+MODEL=[ADD|DEL|UPDATE] modelID,attrId,{acqType,regLen,regAddr,dataOffset,dataLen}");
#if defined(CONFIG_DTU_485)
        COMMAND_HANDLER(ATTR, "AT+ATTR=attrID,CMD[<16,[ADDR],[REG],[CRC]]");
        COMMAND_HANDLER(DEBUG, "AT+DEBUG=CMD[<16],CRC");
        COMMAND_HANDLER(ACQ, "AT+ACQ=CMD[<16],CRC");
#endif

#if defined(CONFIG_DTU_AI)
        COMMAND_HANDLER(AI, "AT+AI=");
#endif

#if defined(CONFIG_DTU_DOUT)
        COMMAND_HANDLER(DOUT, "AT+DOUT=");
#endif

#if defined(CONFIG_DTU_DIN)
        COMMAND_HANDLER(DIN, "AT+DIN=");
#endif
    } else {
        return CL_FAIL;
    }
}

void AtSendResponse(uint8_t* buf, uint16_t len)
{
    AT_COMMAND_SEND_DATA(buf, len);
}

void App_Service_At_Command_Process(void)
{
    uint8_t commandDataLen = 0;

    if ((AtCommandState & AT_COMMAND_RX_DONE_MASK) == AT_COMMAND_RX_DONE_MASK) {
        commandDataLen = AtCommandState & 0x3FF;

        if ((('A' == AtCommandBuf[0] || 'a' == AtCommandBuf[0]) && ('T' == AtCommandBuf[1] || 't' == AtCommandBuf[1]) &&
             ('\r' == AtCommandBuf[2])) ||
            ('\n' == AtCommandBuf[2]) || ('\0' == AtCommandBuf[2])) {
            /* AT command format is 'AT' and returns "OK" directly. Set Output
             * Buffer Param */
            LOG_PRINTF(LL_DEBUG, "OK\r\n");

            memset(AtCommandBuf, 0, sizeof(AtCommandBuf));
            AtCommandState = 0;
            return;
        }

        if (App_At_Command_Parase(AtCommandBuf, commandDataLen) != CL_OK) {
            /* AT command format is invalid and returns "ERROR" directly. Set
             * Output Buffer Param */
            LOG_PRINTF(LL_DEBUG, "ERROR, parse error! parseCommand = %s\r\n", AtCommandBuf);
        }
        memset(AtCommandBuf, 0, sizeof(AtCommandBuf));
        AtCommandState = 0;
    }
}
